package com.test.source;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 可变属性源类，存储并管理多个属性源
 */
public class MutablePropertySources implements PropertySources{

    // 存储属性源的列表，使用CopyOnWriteArrayList以支持并发修改
    private final List<PropertySource<?>> propertySources;

    /**
     * 默认构造函数，创建一个空的属性源列表
     */
    public MutablePropertySources() {
        this.propertySources = new CopyOnWriteArrayList<>();
    }

    /**
     * 构造函数，用给定的属性源列表初始化
     *
     * @param propertySources 初始属性源列表
     */
    public MutablePropertySources(List<PropertySource<?>> propertySources){
        this.propertySources = new CopyOnWriteArrayList<>(propertySources);
    }

    /**
     * 获取属性源列表的副本
     *
     * @return 属性源列表的副本
     */
    public List<PropertySource<?>> getPropertySources() {
        return new ArrayList<>(this.propertySources);
    }

    /**
     * 在列表开头添加属性源
     *
     * @param propertySource 要添加的属性源
     */
    public void addFirst(PropertySource<?> propertySource) {
        removeIfPresent(propertySource);
        this.propertySources.add(0, propertySource);
    }

    /**
     * 在列表末尾添加属性源
     *
     * @param propertySource 要添加的属性源
     */
    public void addLast(PropertySource<?> propertySource) {
        removeIfPresent(propertySource);
        this.propertySources.add(propertySource);
    }

    /**
     * 在指定属性源之前添加属性源
     *
     * @param relativePropertySourceName 相对属性源名称
     * @param propertySource             要添加的属性源
     */
    public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
        assertLegalRelativePropertySourceName(relativePropertySourceName, propertySource);
        removeIfPresent(propertySource);
        int index = indexOf(relativePropertySourceName);
        if (index == -1) {
            throw new IllegalArgumentException("属性源 [" + relativePropertySourceName + "]不存在");
        }
        this.propertySources.add(index + 1, propertySource);
    }

    /**
     * 替换指定名称的属性源
     *
     * @param name            要替换的属性源名称
     * @param propertySource  新的属性源
     */
    public void replace(String name , PropertySource<?> propertySource){
        int index = indexOf(name);
        if (index == -1) {
            throw new IllegalArgumentException("属性源 [" + name + "]不存在");
        }
        this.propertySources.set(index, propertySource);
    }

    /**
     * 移除指定名称的属性源
     *
     * @param name 属性源名称
     * @return 被移除的属性源，如果不存在则返回null
     */
    public PropertySource<?> remove(String name) {
        int index = indexOf(name);
        if (index != -1) {
            return this.propertySources.remove(index);
        }
        return null;
    }

    /**
     * 获取指定名称的属性源
     *
     * @param name 属性源名称
     * @return 对应的属性源，如果不存在则返回null
     */
    @Override
    public PropertySource<?> get(String name) {
        for (PropertySource<?> propertySource : this.propertySources){
            if (propertySource.getName().equals(name)){
                return propertySource;
            }
        }
        return null;
    }

    /**
     * 检查是否包含指定名称的属性源
     *
     * @param name 属性源名称
     * @return 如果包含则返回true，否则返回false
     */
    @Override
    public boolean contains(String name) {
        return this.propertySources.stream()
                .anyMatch(propertySource -> propertySource.getName().equals(name));
    }

    /**
     * 获取属性源列表的迭代器
     *
     * @return 属性源列表的迭代器
     */
    @Override
    public Iterator<PropertySource<?>> iterator() {
        return this.propertySources.iterator();
    }

    /**
     * 如果属性源已存在，则将其移除
     *
     * @param propertySource 要检查并移除的属性源
     */
    private void removeIfPresent(PropertySource<?> propertySource) {
        this.propertySources.removeIf(source -> source.getName().equals(propertySource.getName()));
    }

    /**
     * 断言相对属性源名称和属性源的合法性
     *
     * @param relativePropertySourceName 相对属性源名称
     * @param propertySource             属性源
     */
    private void assertLegalRelativePropertySourceName(String relativePropertySourceName, PropertySource<?> propertySource) {
        if (relativePropertySourceName == null){
            throw new IllegalArgumentException("相对属性源名称不能为空");
        }
        if (propertySource == null){
            throw new IllegalArgumentException("属性源不能为空");
        }
        if (relativePropertySourceName.equals(propertySource.getName())){
            throw new IllegalArgumentException("相对属性源名称不能与属性源名称相同");
        }
    }

    /**
     * 获取指定名称的属性源在列表中的索引
     *
     * @param name 属性源名称
     * @return 属性源的索引，如果不存在则返回-1
     */
    private int indexOf(String name) {
        for (int i = 0; i < this.propertySources.size(); i++) {
            if (this.propertySources.get(i).getName().equals(name)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 以字符串形式返回属性源列表的内容
     *
     * @return 属性源列表的字符串表示
     */
    @Override
    public String toString() {
        return this.propertySources.toString();
    }
}
